package im.youni.horus.dubbo;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.dubbo.rpc.*;
import com.alibaba.dubbo.rpc.support.RpcUtils;
import im.youni.horus.core.SecondTag;
import im.youni.horus.core.common.ServerPortUtils;
import im.youni.horus.core.http.HttpServer;
import im.youni.horus.core.module.Discover;
import im.youni.horus.core.module.GlobalConfig;
import im.youni.horus.core.module.Hook;
import im.youni.horus.core.recoder.RecordFactory;
import im.youni.horus.core.recoder.SyncRecord;

@Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
public class MonitorFilter implements Filter {

    RecordFactory maintainer = RecordFactory.getInstance();

    public MonitorFilter() {
        try{
            String consulHost = Configer.getValue("consul.host");
            int port = ServerPortUtils.getAvailablePort();
            // 初始化全局配置
            GlobalConfig.getInstance().initConfig(consulHost, NetUtils.getLocalHost(), port);
            // 启动http
            HttpServer.initServer(port);
            // 服务发现注册
            Discover.registry();
            // 服务发现注销钩子
            Hook.shutdown();
            // 启动metircs同步
            new SyncRecord(30000);
            System.out.println("YMonitorFilter started, http port:" + port + "|" + consulHost);
        } catch (Exception ex){
            System.out.println(ex);
            // 启动monitor异常，打印堆栈
            //ex.printStackTrace();
        }

    }

    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // 提供方必须在invoke()之前获取context信息
        RpcContext context = RpcContext.getContext();
        // 记录起始时间戮
        long start = System.currentTimeMillis();
        try {
            // 让调用链往下执行
            Result result = invoker.invoke(invocation);
            collect(invoker, invocation, result, context, start, 0, 0);
            return result;
        } catch (RpcException e) {
            collect(invoker, invocation, null, context, start, 101, e.getCode());
            throw e;
        }
    }

    /**
     * 信息采集
     * @param invoker
     * @param invocation
     * @param result
     * @param context
     * @param start
     * @param errorType
     * @param errorCode
     */
    private void collect(Invoker<?> invoker, Invocation invocation, Result result, RpcContext context, long start, int errorType, int errorCode) {
        try {
            // ---- 服务信息获取 ----
            long elapsed = System.currentTimeMillis() - start; // 计算调用耗时
            String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
            String service = invoker.getInterface().getName(); // 获取服务名称
            String method = RpcUtils.getMethodName(invocation); // 获取方法名
            long time = System.currentTimeMillis() / 1000;

            SecondTag tag = new SecondTag(time, application, service, method, NetUtils.getLocalHost(), errorType, errorCode);
            maintainer.getRecorder(tag).record((int) elapsed);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}